/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools nat
 */

#include "compare_nat.h"

#include <memory>
#include <cinttypes>
#include <cmath>
#include <string>
#include <sys/types.h>

#include "hmfs_log.h"
#include "hmfs_utils.h"
#include "io.h"
#include "securec.h"

namespace OHOS {
namespace Hmfs {
int32_t CompareNat::CompareNatArea()
{
    if (ReadNatArea(srcInfo_)) {
        HMFS_ERROR("Failed to read nat area.");
        return -1;
    }
    if (ReadNatArea(dstInfo_)) {
        HMFS_ERROR("Failed to read nat area.");
        return -1;
    }

    NatBlockData* srcNat = reinterpret_cast<NatBlockData*>(srcInfo_.natPos);
    NatBlockData* dstNat = reinterpret_cast<NatBlockData*>(dstInfo_.natPos);
    if (CompareNatBlockData(srcNat, dstNat)) {
        HMFS_ERROR("Nat block data not equal.");
        return -1;
    }

    uint64_t remainderBufSize = natBufferSize_ - HMFS_BLOCK_SIZE;
    if (memcmp(srcInfo_.natPos, dstInfo_.natPos, remainderBufSize)) {
        HMFS_ERROR("Nat remainder buf not equal, at offset 0x%" PRIx64 ", len = 0x%" PRIx64 "",
            srcInfo_.natOffset + HMFS_BLOCK_SIZE, remainderBufSize);
    }

    return 0;
}

int32_t CompareNat::ReadNatArea(FsData &fsInfo)
{
    fsInfo.natOffset = GetLeValue(fsInfo.superBlock->natBlockId) * HMFS_BLOCK_SIZE;
    HMFS_INFO("natOffset = 0x%" PRIx64 ".", fsInfo.natOffset);

    natBufferSize_ = (GetLeValue(fsInfo.superBlock->segmentCountInNAT) << GetLeValue(fsInfo.superBlock->logBlksPerSeg)) * HMFS_BLOCK_SIZE;
    fsInfo.natBuf = std::make_unique<char[]>(natBufferSize_);
    fsInfo.natPos = fsInfo.natBuf.get();

    if (DevRead(fsInfo, fsInfo.natBuf.get(), fsInfo.natOffset, natBufferSize_)) {
        HMFS_ERROR("Failed to read nat area.");
        return -1;
    }

    return 0;
}

int32_t CompareNat::CompareNatBlockData(NatBlockData *srcNat, NatBlockData *dstNat)
{
    for (uint32_t i = 0; i < NAT_ENTRIES_PER_BLOCK; i++) {
        COMPARE_NUMBER(srcNat, dstNat, entries[i].version, i);
        COMPARE_NUMBER(srcNat, dstNat, entries[i].inodeNumber, i);
        COMPARE_NUMBER(srcNat, dstNat, entries[i].blockId, i);
    }

    srcInfo_.natPos += HMFS_BLOCK_SIZE;
    dstInfo_.natPos += HMFS_BLOCK_SIZE;
    return 0;
}
} // namespace Hmfs
} // namespace OHOS
